<script lang="jsx" setup>
import { read } from 'xlsx/xlsx.mjs';
import { computed, defineAsyncComponent, ref } from 'vue';
import { Button, Empty } from 'ant-design-vue';
import { toFormData } from '@/net/requ.js';
import { FileTextOutlined, FileExcelOutlined, DeleteOutlined, UserOutlined } from '@ant-design/icons-vue';
import { REQU, useResp, SignInInfoInvalidCondPair, getTaskInfo, getUserInfo } from '@/net/requ.js';
import { message } from 'ant-design-vue';
import router from '@/router';
import { taskOptions, assignStatusOptions } from '@/util/const.js';
import { OptionsFlatted, strToArr, optsToDic, asgmntEq, asgmntGte, asgmntLt } from '@/util/index.js';
import { useClasses } from './api/use-classes.jsx';
import { useLabelEditor } from './api/use-editor.js';
import { useImageClasses } from './api/use-image-classes.js';
import { Pairs } from '@/util/xls.js';
const DataTag = defineAsyncComponent(() => import('./components/data-tag.vue'));
const StaffDialog = defineAsyncComponent(() => import('./components/staff-dialog/index.vue'));
const LabelEditor = defineAsyncComponent(() => import('./components/label-editor.vue'));

const props = defineProps(['id']);
const asgmntDic = optsToDic(assignStatusOptions);

const loading = ref(false);
const userInfo = JSON.parse(localStorage.getItem('userInfo'));

const staffTree = ref([{ title: '标注团队', key: 'all' }]);
const flatted = OptionsFlatted(taskOptions);
const TaskTypeTxt = R.propOr('--', R.__, optsToDic(flatted));

const formElem = ref();
const formState = ref({
  id: R.propOr('', 'id', props),
  assignmentStatus: asgmntDic['未分配'],
  taskName: '',
  orgId: R.propOr('', 'orgId', userInfo),
  type: taskOptions[0].options[0].value,
  classes: [],
  imageClasses: new Set(),
  staff: [],
});
const ids = computed(() => R.pluck('id', formState.value.staff));
const { classesColumns, fromStorable: classesFromStorable, toStorable: classesToStorable } = useClasses({ loading });
const { labelEditorProps, showLabelEditor } = useLabelEditor();
const { loadImageClasses } = useImageClasses({ formState });

const rules = {
  taskName: [ { required: true, message: '请输入任务名称', trigger: 'change' } ],
  staff: [{
    validator: async (rule, v) => 0 < v.length
      ? Promise.resolve()
      : Promise.reject('请选择标注人员')
  }],
  classes: [{
    validator: async (rule, v) => 0 < v.length
      ? Promise.resolve()
      : Promise.reject('请添加标签')
  }],
}

function getStaffTree() {
  REQU(`/api/group/treeList?`)
  .then(useResp({
    succ: result => {
      staffTree.value[0].children = R.transduce(
        R.addIndex(R.map)((o, i) => Object.assign({}, o, { key: `group-${i}` })),
        R.flip(R.append),
        [],
        result.data
      );
    },
    fail: R.cond([SignInInfoInvalidCondPair()]),
  }))
}

function save() {
  loading.value = true;
  return REQU('/api/task/save', {
    method: 'POST',
    body: toFormData(
      R.mergeDeepRight(
        R.pick(['id','assignmentStatus','taskName','orgId','type'], formState.value),
        {
          labels: classesToStorable(formState.value.classes),
          // labels: R.pluck('label', formState.value.classes),
          userIds: R.pluck('id', formState.value.staff),
          imageCategories: Array.from(formState.value.imageClasses).join(','),
        }
      )
    )
  })
  .finally(() => loading.value = false)
}

function onSubmit() {
  formElem.value.validate()
  .then(save)
  .then(useResp({
    succ: () => {
      message.success(`${ props.id ? '编辑' : '新建' }任务完成`);
      router.push('/task');
    },
    fail: R.cond([SignInInfoInvalidCondPair()]),
  }))
  .catch(() => {});
}

const OpCol = () => ({
  title: '操作',
  width: '3.5em',
  customRender: ({ record }) => (
    <Button
      type="link"
      onClick={() => formState.value.staff.splice( formState.value.staff.indexOf(record), 1 )}>
      {{ icon: () => <DeleteOutlined style="color: rgb(200,0,0);" /> }}
    </Button>
  ),
});

const staffColumns = computed(() => (
  // 创建或编辑未分配的任务时，可编辑人员
  !props.id || asgmntEq('未分配', formState.value)
  ? [{ title: '姓名', dataIndex: 'realName' }, OpCol()]
  : [{ title: '姓名', dataIndex: 'realName' }]
));

const staffDialogProps = ref({ visible: false });

function main() {
  getStaffTree();

  if (!props.id) { return; }

  loading.value = true;
  getTaskInfo(props.id).then(useResp({
    succ: result => {
      Object.assign( formState.value, R.pick(['assignmentStatus','taskName','type'], result.data) );
      formState.value.classes = classesFromStorable(result.data.labels);
      formState.value.imageClasses = new Set( strToArr(R.split(','))(result.data.imageCategories) );

      return result.data.tagUserIds.split(',');
    }
  }))
  .then(userIds => Promise.all( userIds.map(getUserInfo) ))
  .then(userInfos => (formState.value.staff = userInfos))
  .finally(() => loading.value = false);
}

main();

function XlsToTableData(event) {
  const elem = event.currentTarget;
  
  return new Promise(resolve => {
    const fr = new FileReader();
    fr.readAsArrayBuffer(elem.files[0]);
    fr.addEventListener('load', 
      R.compose(
        resolve,
        R.map(R.zipObj(['label', 'limit'])),
        Pairs,
        R.path(['Sheets', 'Sheet1']),
        read,
        R.path(['target', 'result'])
      )
    );
  })
}

const loadClasses = R.compose( R.andThen(xs => (formState.value.classes = xs)), XlsToTableData );
</script>

<template>
  <div class="task-edit">
    <a-spin :spinning="loading">
      <a-form
        ref="formElem"
        layout="vertical"
        :model="formState"
        :rules="rules"
        :colon="false">
        <a-form-item required name="taskName" label="任务名称">
          <a-input
            v-model:value="formState.taskName"
            :disabled="loading"
            autocomplete="off"
            allow-clear
            placeholder="请输入任务名称">
          </a-input>
        </a-form-item>

        <a-form-item required name="type" label="所属类别">
          <template v-if="asgmntGte('已分配', formState)">
            <span style="padding-left: 1em;">{{ TaskTypeTxt(formState.type) }}</span>
          </template>
          <template v-else>
            <a-select
              v-model:value="formState.type"
              :disabled="loading"
              :options="taskOptions"
              placeholder="请选择"
            >
            </a-select>
          </template>
        </a-form-item>

        <a-form-item name="staff" class="help-front">
          <template #label>
            <span>标注人员</span>
            <!-- 和 已分配 对立的不只有 未分配，可能有 null -->
            <template v-if="asgmntLt('已分配')">
              <a-button
                type="link"
                :disabled="loading"
                @click="() => staffDialogProps.visible = true">
                <template #icon><user-outlined /></template>
                选择
              </a-button>
            </template>
          </template>
          <a-table
            bordered
            :show-header="false"
            :pagination="false"
            size="small"
            row-key="id"
            :data-source="formState.staff"
            :columns="staffColumns"
            :scroll="{ y: 300 }">
            <template #emptyText>
              <a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE">
                <template #description>请添加标注人员</template>
              </a-empty>
            </template>
          </a-table>
        </a-form-item>
    
        <a-form-item name="classes" class="help-front">
          <template #label>
           <span>数据标签</span>
            <label>
              <input type="file" accept=".xls,.xlsx" hidden @change="loadClasses">

              <a-button
                type="link"
                :disabled="loading"
                @click="event => event.currentTarget.parentElement.click()">
                <template #icon><file-excel-outlined /></template>
                导入
              </a-button>
            </label>

            <a-button
              type="danger"
              ghost
              :disabled="loading"
              size="small"
              style="border: 0;"
              @click="() => (formState.classes = [])">
              <template #icon><delete-outlined /></template>
              清空
            </a-button>
          </template>
          <a-form-item-rest>
            <a-table
              bordered
              :pagination="false"
              size="small"
              row-key="label"
              :data-source="formState.classes"
              :columns="classesColumns">
              <template #emptyText>
                <a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE">
                  <template #description>请添加标签</template>
                </a-empty>
              </template>
            </a-table>
          </a-form-item-rest>
        </a-form-item>

        <a-form-item name="imageClasses" class="help-front">
          <template #label>
           <span>图片标签</span>
            <label>
              <input type="file" accept=".txt" hidden @change="loadImageClasses">

              <a-button
                type="link"
                :disabled="loading"
                @click="event => event.currentTarget.parentElement.click()">
                <template #icon><file-text-outlined /></template>
                导入
              </a-button>
            </label>

            <a-button
              type="danger"
              ghost
              :disabled="loading"
              size="small"
              style="border: 0;"
              @click="() => formState.imageClasses.clear()">
              <template #icon><delete-outlined /></template>
              清空
            </a-button>
          </template>
          <div class="tag-container">
            <label-editor
              v-if="labelEditorProps.visible && 'imageClasses' == labelEditorProps.name"
              v-model:visible="labelEditorProps.visible"
              @ok="label => formState.value.imageClasses.add(label)">
            </label-editor>
            <!-- <a-button
              type="dashed"
              :disabled="loading"
              @click="showLabelEditor">
              + 标签
            </a-button> -->
            <template v-if="!formState.imageClasses.size">
              <span class="empty-txt">请添加标签</span>
            </template>

            <template v-for="(label, i) in formState.imageClasses" :key="i">
              <data-tag
                :label="label"
                @remove="label => formState.imageClasses.delete(label)">
              </data-tag>
            </template>
          </div>
        </a-form-item>

        <staff-dialog
          v-if="staffDialogProps.visible"
          v-model:visible="staffDialogProps.visible"
          :staff-tree="staffTree"
          :ids="ids"
          @ok="staff => formState.staff = staff">
        </staff-dialog>

        <a-button html-type="submit" :disabled="loading" type="primary" @click="onSubmit">完成</a-button>
      </a-form>
    </a-spin>
  </div>
</template>

<style>
.task-edit {
  width: 900px;
  padding: 24px;
  margin: 24px auto;
  background: #fff;
}

.task-edit .ant-form-item.help-front .ant-form-item-control > :first-child {
  order: 2;
  margin-top: .5em;
  margin-bottom: 1em;
}

.task-edit .tag-container {
  position: relative;
  display: flex;
  align-content: flex-start;
  flex-wrap: wrap;
  gap: 1em;
  overflow-y: auto;
  height: 200px;
  padding: 1em;
  border: 1px solid rgb(228,228,228);
  border-radius: 4px;
}

.task-edit .tag-container > .empty-txt {
  position: absolute;
  top: 40%;
  left: 0;
  right: 0;
  width: 5em;
  margin: auto;
  color: rgba(0,0,0,.5);
}

.task-edit .tag-editor {
  z-index: 1;
  position: absolute;
  top: 14px;
  left: 1em;
}

.task-edit [type="submit"]:last-child {
  display: block;
  width: 10em;
  margin-left: auto;
  margin-right: auto;
}
</style>
